package org.ihelpuoo.orm;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletRequest;

import org.apache.log4j.Logger;
import org.ihelpuoo.core.Nut;
import org.ihelpuoo.db.ConnectionPool;
import org.ihelpuoo.db.ConnectionProxy;
import org.ihelpuoo.db.sql.SQLNotFoundException;
import org.ihelpuoo.db.sql.SQLSegment;
import org.ihelpuoo.orm.filter.FieldFilter;
import org.ihelpuoo.orm.filter.Filter;
import org.ihelpuoo.orm.filter.SQLFilter;
import org.ihelpuoo.util.Pager;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class POJO
{
	private static Logger	log	= Logger.getLogger(POJO.class);

	private Nut				nut;
	private III				iii;
	private ConnectionPool	pool;

	public POJO(Nut nut, III iii, ConnectionPool pool)
	{
		this.nut = nut;
		this.iii = iii;
		this.pool = pool;
	}

	public Nut nut()
	{
		return nut;
	}

	public Connection getConnection()
	{
		return pool.getConnection();
	}

	public void execute(String sql)
	{
		ConnectionProxy conn = null;
		try
		{
			conn = pool.pick();
			if (log.isDebugEnabled())
				log.debug(sql);
			conn.execute(sql);
			conn.close();
			conn = null;
		}
		catch (Exception e)
		{
			safeCloseConnection(conn,log);
		}
	}

	public SQLSegment getSQL(String key) throws SQLNotFoundException
	{
		return pool.sqls().get(key);
	}

	public ObjectRule getRule(Class type) throws IIIException
	{
		ObjectRule rule = iii.manual.getRule(type);
		Connection conn = null;
		try
		{
			conn = getConnection();
			rule.checkDatabaseConfig(conn,null);
			conn.close();
			return rule;
		}
		catch (SQLException e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			safeCloseConnection(conn,log);
		}
	}

	public boolean isNewIsDB(Object obj) throws IIIException
	{
		return this.getRule(obj.getClass()).isNewInDB(obj);
	}

	@Deprecated
	public III iii()
	{
		return iii;
	}

	public boolean clear(Class type, Object refer) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			boolean re = iii.clear(conn,type,refer);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public boolean clear(Class type) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			boolean re = iii.clear(conn,type);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public boolean clearDeeply(Class type, Object refer) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			boolean re = iii.clearDeeply(conn,type,refer);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public boolean clearDeeply(Class type) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			boolean re = iii.clearDeeply(conn,type);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public int count(Class type, Object refer) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			int re = iii.count(conn,type,refer);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public int count(Class type, SQLFilter filter, Object refer) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			int re = iii.count(conn,type,filter,refer);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public int count(Class type) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			int re = iii.count(conn,type);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public List deleteBatch(Class type, SQLFilter filter, FieldFilter ignore) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			List re = iii.deleteBatch(conn,type,filter,ignore,null);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public List deleteBatch(Class type, SQLFilter filter, FieldFilter ignore, Object refer)
			throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			List re = iii.deleteBatch(conn,type,filter,ignore,refer);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public boolean delete(Object obj, FieldFilter ignore) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			boolean re = iii.delete(conn,obj,ignore);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public Object fetch(Object obj, FieldFilter actived, FieldFilter locked) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			Object re = iii.fetch(conn,obj,actived,locked);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public Object fetch(Object obj) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			Object re = iii.fetch(conn,obj);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public Object fetch(Map map, Object obj, FieldFilter actived, FieldFilter locked)
			throws IIIException
	{
		return iii.fetch(map,obj,actived,locked);
	}

	public Object fetch(ResultSet rs, Object obj, FieldFilter actived, FieldFilter locked)
			throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			Object re = iii.fetch(conn,rs,obj,actived,locked);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public Object fetch(Document doc, Object obj) throws IIIException
	{
		return iii.fetch(doc,obj);
	}

	public Object fetch(Element ele, Object obj) throws IIIException
	{
		return iii.fetch(ele,obj);
	}

	public List query(Class type, Filter filter, FieldFilter actived, FieldFilter locked,
			Pager pager, Object refer) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			List re = iii.query(conn,type,filter,actived,locked,pager,refer);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public List query(Class type, Filter filter, FieldFilter actived, FieldFilter locked,
			Pager pager) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			List re = iii.query(conn,type,filter,actived,locked,pager);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public List query(Class type, Filter filter, Pager pager, Object refer) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			List re = iii.query(conn,type,filter,pager,refer);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public List query(Class type) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			List re = iii.query(conn,type);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public List query(Object obj) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			List re = iii.query(conn,obj);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public List query(Object obj, FieldFilter actived, FieldFilter locked, Pager pager, Object refer)
			throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			List re = iii.query(conn,obj,actived,locked,pager,refer);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public List query(Element ele, Class type, Filter filter, FieldFilter actived,
			FieldFilter locked, Pager pager, Object refer) throws IIIException
	{
		return iii.query(ele,type,filter,actived,locked,pager,refer);
	}
	
	public List query(Element ele, Class type) throws IIIException
	{
		return iii.query(ele,type,null,null,null,null,null);
	}

	public List save(List list, FieldFilter actived, FieldFilter locked) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			List re = iii.save(conn,list,actived,locked);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public List save(List list) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			List re = iii.save(conn,list);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public Object save(Object obj, FieldFilter actived, FieldFilter locked) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			Object re = iii.save(conn,obj,actived,locked);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public List save(Object... list) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			List re = iii.save(conn,list);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public Object save(Object obj) throws IIIException
	{
		Connection conn = null;
		try
		{
			conn = pool.getConnection();
			Object re = iii.save(conn,obj);
			conn.close();
			conn = null;
			return re;
		}
		catch (Exception e)
		{
			throw IIIException.wrap(e);
		}
		finally
		{
			POJO.safeCloseConnection(conn,log);
		}
	}

	public Object fetch(ServletRequest request, Object obj) throws IIIException
	{
		return iii.fetch(request,obj);
	}

	public Object fetch(ServletRequest request, Object obj, FieldFilter actived, FieldFilter locked)
			throws IIIException
	{
		return iii.fetchObject(request,obj,actived,locked);
	}

	public Object fetchByXMLFileName(String fn, Object obj, FieldFilter actived, FieldFilter locked)
			throws IIIException
	{
		return iii.fetchByXMLFileName(fn,obj,actived,locked);
	}

	public Document createDocument(Object obj) throws IIIException
	{
		return iii.createDocument(obj);
	}

	public Document createDocument(Object obj, FieldFilter actived, FieldFilter locked)
			throws IIIException
	{
		return iii.createDocument(obj,actived,locked);
	}

	public Document createDocument(List list, FieldFilter actived, FieldFilter locked)
			throws IIIException
	{
		return iii.createDocument(list,actived,locked);
	}

	public Document createDocument(List list) throws IIIException
	{
		return iii.createDocument(list);
	}

	public List insert(Element ele, List list, FieldFilter actived, FieldFilter locked)
			throws IIIException
	{
		return iii.insert(ele,list,actived,locked);
	}

	public List insert(Element ele, List list) throws IIIException
	{
		return iii.insert(ele,list,null,null);
	}

	public Object insert(Element ele, Object obj, FieldFilter actived, FieldFilter locked)
			throws IIIException
	{
		return iii.insert(ele,obj,actived,locked);
	}

	public Object insert(Element ele, Object obj) throws IIIException
	{
		return iii.insert(ele,obj);
	}

	/**
	 * A final method to close a connection, if the connection is null
	 * do nothing.
	 * 
	 * @param conn: Connection
	 * @param log: a logger, if any Exception rised, it will write the detail
	 * 			   message.
	 */
	public static void safeCloseConnection(Connection conn, Logger log)
	{
		if (null != conn)
		{
			try
			{
				conn.close();
			}
			catch (SQLException e)
			{
				log.error("Fail to close connection:" + e.getMessage());
			}
		}
	}

	public static void safeCloseConnection(Connection conn)
	{
		safeCloseConnection(conn,log);
	}

}
